package com.straw.hat.com.straw.hat.jdk.concurrent.forkjoin;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * company: 鲸灵科技
 * author: qiyue@webuy.ai
 * date: 2019/9/28
 * time: 11:26 PM
 */
public class SortForkJoinStudy {


    private static final Integer CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final ForkJoinPool FORK_JOIN_POOL = new ForkJoinPool(CPU_COUNT);
    private static final Random  random = new Random();

    public static void main(String[] args) {
        try {
            /*经过测试100000级别 两个排序性能是差不多的 小于情况forkJoin好 大于的情况parallelStream().sorted()好*/
            List<Integer> list = new ArrayList<>(100000);
            for (int i = 0; i < 100000; i++) {
                int num = random.nextInt(100000) + 1;
                list.add(num);
            }
//            System.out.println("-----------------------------------");
//            Long startA  = System.currentTimeMillis();
//            List<Integer> resultA = list.parallelStream().sorted().collect(Collectors.<Integer>toList());
//            resultA.stream().forEach(num -> System.out.print(""));
//            long spendA = System.currentTimeMillis() - startA;
//            System.out.println("spend time : "+ Long.valueOf(spendA));


            System.out.println("-----------------------------------");
            Long starB  = System.currentTimeMillis();
            ForkJoinTask<List<Integer>> resultB = FORK_JOIN_POOL.submit(new SumTask(list));
            resultB.get().stream().forEach(num -> System.out.print(""));
            long spendB = System.currentTimeMillis() - starB;
            System.out.println("spend time : "+ Long.valueOf(spendB));
            System.in.read();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    static class SumTask extends RecursiveTask<List<Integer>> {

        private static final Integer THRESHOLD = 10;

        private List<Integer> list;
        public SumTask (List<Integer> list){
            this.list = list;
        }

        @Override
        protected List<Integer> compute() {
            try {
                if (list != null && list.size() <= THRESHOLD) {
                    System.out.println(Thread.currentThread().getName());
                    return list.parallelStream().sorted().collect(Collectors.<Integer>toList());
                } else if (list != null){
                    int size = list.size();
                    Integer mid = (size + 0) /2;
                    List<Integer> partitionA = list.subList(0,mid);
                    List<Integer> partitionB = list.subList(mid,size);
                    SumTask subSumTaskA = new SumTask(partitionA);
                    SumTask subSumTaskB = new SumTask(partitionB);
                    /*同步等待*/
                    subSumTaskA.fork();
                    subSumTaskB.fork();
                    List<Integer> resultA = subSumTaskA.join();
                    List<Integer> resultB = subSumTaskB.join();
                    /*把好序的两个list重新组合*/
                    List<Integer> result = mergeSort(resultA,resultB);
                    return result;
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }



        /*并归排序*/
        private List<Integer> mergeSort(List<Integer> resultA, List<Integer> resultB) {
            List<Integer> result = new ArrayList<>();
            int sizeA = resultA.size();
            int sizeB = resultB.size();
            Integer [] arrayA = new Integer[sizeA];
            Integer [] arrayB = new Integer[sizeB];
            Integer[] intArrA = resultA.toArray(arrayA);
            Integer[] intArrB = resultB.toArray(arrayB);
            Integer[] intArrK = new Integer[sizeA+sizeB];
            int a = 0  , b = 0 , k = 0;
            while (a < sizeA && b < sizeB) {
                if (intArrA[a] < intArrB [b]) {
                    intArrK[k++] = intArrA[a++];
                } else {
                    intArrK[k++] = intArrB[b++];
                }
            }
            /*A还没有添加完成*/
            while (a < sizeA){
                intArrK[k++] = intArrA[a++];
            }
            /*B还没有添加完成*/
            while (b < sizeB) {
                intArrK[k++] = intArrB[b++];
            }
            result.addAll(Arrays.asList(intArrK));
            return result;
        }
    }
}
